//
// Created by lz on 2/27/21.
//

#include "net/Channel.h"
#include "base/Logging.h"
#include "net/EventLoop.h"

#include <sstream>
#include <poll.h>

using namespace lzweb;
using namespace lzweb::net;

const int Channel::kNoneEvent = 0;

const int Channel::kReadEvent = POLLIN | POLLPRI; // POLLPRI用于读取紧急数据(POLLIN好像也会响应紧急数据的读取)
const int Channel::kWriteEvent = POLLOUT;

//构造函数初始化成员
Channel::Channel(EventLoop* loop, int fd)
	: loop_(loop),
	  fd_(fd),
	  events_(0),
	  revents_(0),
	  index_(-1),
	  logHup_(true),
	  tied_(false),
	  eventHandling_(false),
	  addedToLoop(false)
{
}

//析构函数检查对象的成员的一些状态
Channel::~Channel()
{
	//保证在该Channel已经不在loop中
	assert(!eventHandling_);
	assert(!addedToLoop);
	if (loop_->isInLoopThread())
	{
		assert(!loop_->hasChannel(this));
	}
}

void Channel::tie(const std::shared_ptr<void>& obj)
{
	tie_ = obj;
	tied_ = true;
}

// update就是把该Channel记录在Loop中
void Channel::update()
{
	addedToLoop = true;
	loop_->updateChannel(this);
}

// remove 把该Channel的记录从loop_中移除
void Channel::remove()
{
	assert(isNoneEvent());
	addedToLoop = false;
	loop_->removeChannel(this);

}

void Channel::handleEvent(TimeStamp receiveTime)
{
	std::shared_ptr<void> guard;


	if(tied_)
	{
		//从weak_ptr升级为shared_ptr
		guard = tie_.lock();
		if(guard)
		{
			handleEventWithGuard(receiveTime);
		}
	}
	else //所以if else的意义是什么？
	{
		handleEventWithGuard(receiveTime);
	}
}

void Channel::handleEventWithGuard(TimeStamp receiveTime)
{
	eventHandling_ = true;
	LOG_TRACE<< reventsToString();

	// POLLHUP 双端关闭， POLLRDHUP读端关闭
	if((revents_&POLLHUP) &&!(revents_ & POLLIN) )
	{
		if(logHup_)
		{
			LOG_WARN << "fd = "<<fd_<<" Channel::handle_event() POLLHUP";
		}
		if(closeCallback_) closeCallback_();
	}

	//POLLNVAL is equivalent to EBADF: it means the file descriptor does not actually refer to any open file,
	// i.e. it was closed or never open to begin with.
	if(revents_ & POLLNVAL)
	{
		LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";
	}

	if (revents_ & (POLLERR | POLLNVAL))
	{
		if (errorCallback_) errorCallback_();
	}
	if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
	{
		if (readCallback_) readCallback_(receiveTime);
	}
	if (revents_ & POLLOUT)
	{
		if (writeCallback_) writeCallback_();
	}
	eventHandling_ = false;
}

string Channel::reventsToString() const
{
	return eventToString(fd_, revents_);
}

string Channel::eventsToString() const
{
	return eventToString(fd_, events_);
}

string Channel::eventToString(int fd, int ev)
{
	std::ostringstream oss;
	oss << fd << ": ";
	if (ev & POLLIN)
		oss << "IN ";
	if (ev & POLLPRI)
		oss << "PRI ";
	if (ev & POLLOUT)
		oss << "OUT ";
	if (ev & POLLHUP)
		oss << "HUP ";
	if (ev & POLLRDHUP)
		oss << "RDHUP ";
	if (ev & POLLERR)
		oss << "ERR ";
	if (ev & POLLNVAL)
		oss << "NVAL ";

	return oss.str();
}






